﻿// -------------------------------------------------------------------------------------------------
// <copyright file="TVSeries.cs" company="HeterogeneousComputing.com">
// Creative Commons Attribution-ShareAlike 3.0 Unported License
// </copyright>
//
// <author>Jock</author>
//
// <date>04/08/2011</date>
//
// <summary>Implements the tv series class</summary>
// -------------------------------------------------------------------------------------------------
namespace TheTVDBScraper
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using System.Runtime.Serialization; 
    using System.Text;
    using NLog;

    /// <summary>
    /// Class representing a TVSeries.
    /// </summary>
    [DataContract(Name = "TVSeries",
        Namespace = "http://www.heterogeneouscomputing.com/TheTVDBScraper", IsReference = true)]
    public class TVSeries : IJobRoleCapable, IExtensibleDataObject
    {
        #region Private Fields

            /// <summary> Confirgure NLog logging.  </summary>
            private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();

            /// <summary> The extension data object value. </summary>
            private ExtensionDataObject extensionDataObject_value;

            /// <summary>
            /// Attribute that uniquely identifes this TVSeries
            /// on TheTVDB.
            /// </summary>
            private string id;

            /// <summary> Our unique key which is the same as the seriesId </summary>
            private Guid key;
            /// <summary>
            /// Attribute that uniquely identifes this TVSeries
            /// on TheTVDB (Seems to be the same as id).
            /// </summary>
            private string seriesId;

            /// <summary>
            /// The name of this TVSeries
            /// on TheTVDB.
            /// </summary>
            private string seriesName;

            /// <summary>
            /// The description or Overview of this TVSeries.
            /// </summary>
            private string overview;

            /// <summary>
            /// The language of this TVSeries.
            /// </summary>
            private string language;

            /// <summary>
            /// Attribute that captures the first airing or viewing date
            /// that the TVSeries was broadcast.
            /// </summary>
            private string firstAired;

            /// <summary>
            /// Attribute that gives the URL of the banner for the TVSeries.
            /// </summary>
            private string banner;

            /// <summary>
            /// Attribute that uniquely identifes this TVSeries
            /// on IMDb.
            /// </summary>
            private string imdbId;

            /// <summary>
            /// Attribute that uniquely identifes this TVSeries
            /// on Zap2It.
            /// </summary>
            private string zap2itId;

            /// <summary>
            /// Attribute that collects a list of the known Seasons for this TVSeries.
            /// </summary>
            private Dictionary<string, TVSeason> seasonDictionary = 
                new Dictionary<string, TVSeason>();

            /// <summary>
            /// Attribute that captures the day of the week that the TV Show was broadcast.
            /// </summary>
            private string airsDayOfWeek;

            /// <summary>
            /// Attribute that captures the time of the day that the TV Show was broadcast.
            /// </summary>
            private string airsTime;

            /// <summary>
            /// Attribute that captures the list of Genre into which this TVSeries falls/is categoised.
            /// </summary>
            private List<Genre> genres = new List<Genre>();

            /// <summary> The characters in this TVSeries. </summary>
            private Dictionary<string, TVCharacter> characterDictionary = new Dictionary<string, TVCharacter>();

        #endregion Private Fields

        #region Public Properties
            /// -------------------------------------------------------------------------------------------------
            /// <summary>   Gets or sets the structure that contains extra data. 
            /// To implement the IExtensibleDataObject interface,
            /// you must implement the ExtensionData property. The property
            /// holds data from future versions of the class for backward
            /// compatibility.</summary>
            /// <value> Information describing the extension. </value>
            /// ### <returns>
            /// An <see cref="T:System.Runtime.Serialization.ExtensionDataObject" /> that contains data that
            /// is not recognized as belonging to the data contract.
            /// </returns>
            /// -------------------------------------------------------------------------------------------------
            public ExtensionDataObject ExtensionData
            {
                get
                {
                    return this.extensionDataObject_value;
                }

                set
                {
                    this.extensionDataObject_value = value;
                }
            }

            /// <summary>
            /// Gets or sets the attribute that uniquely identifes this TVSeries
            /// on TheTVDB.
            /// </summary>
            [DataMember]
            public string Id
            {
                get
                {
                    return this.id;
                }

                set
                {
                    this.id = value;
                    this.key = new Guid();
                }
            }

            /// -------------------------------------------------------------------------------------------------
            /// <summary>   Gets the key for this TVSeries aka the id. </summary>
            /// <value> The unique key. </value>
            /// -------------------------------------------------------------------------------------------------
            public Guid Key
            {
                get
                {
                    return this.key;
                }
            }
            /// <summary>
            /// Gets or sets the attribute that uniquely identifes this TVSeries
            /// on TheTVDB (Seems to be the same as id).
            /// </summary>
            [DataMember]
            public string SeriesId
            {
                get
                {
                    return this.seriesId;
                }

                set
                {
                    this.seriesId = value;
                }
            }

            /// <summary>
            /// Gets or sets the attribute for the name of this TVSeries
            /// on TheTVDB.
            /// </summary>
            [DataMember]
            public string SeriesName
            {
                get
                {
                    return this.seriesName;
                }

                set
                {
                    this.seriesName = value;
                }
            }

            /// <summary>
            /// Gets or sets the description or Overview of this TVSeries.
            /// </summary>
            [DataMember(EmitDefaultValue = false)]
            public string Overview
            {
                get
                {
                    return this.overview;
                }

                set
                {
                    this.overview = value;
                }
            }

            /// <summary>
            /// Gets or sets the language of this TVSeries.
            /// </summary>
            [DataMember]
            public string Language
            {
                get
                {
                    return this.language;
                }

                set
                {
                    this.language = value;
                }
            }

            /// <summary>
            /// Gets or sets the Id that uniquely identifes this TVSeries
            /// on IMDb.
            /// </summary>
            [DataMember(EmitDefaultValue = false)]
            public string IMDBId
            {
                get
                {
                    return this.imdbId;
                }

                set
                {
                    this.imdbId = value;
                }
            }

            /// <summary>
            /// Gets or sets the attribute that gives the URL of the banner for the TVSeries.
            /// </summary>
            [DataMember(EmitDefaultValue = false)]
            public string Banner
            {
                get
                {
                    return this.banner;
                }

                set
                {
                    this.banner = value;
                }
            }

            /// <summary>
            /// Gets or sets the attribute that captures the first airing or viewing date
            /// that the TVSeries was broadcast.
            /// </summary>
            [DataMember(EmitDefaultValue = false)]
            public string FirstAired
            {
                get
                {
                    return this.firstAired;
                }

                set
                {
                    this.firstAired = value;
                }
            }

            /// <summary>
            /// Gets or sets the Id that uniquely identifes this TVSeries
            /// on Zap2ItId.
            /// </summary>
            [DataMember(EmitDefaultValue = false)]
            public string Zap2ItId
            {
                get
                {
                    return this.zap2itId;
                }

                set
                {
                    this.zap2itId = value;
                }
            }

            /// <summary>
            /// Gets or sets the atribute that captures the day of the week
            /// that the TV Show was broadcast on.
            /// </summary>
            [DataMember(EmitDefaultValue = false)]
            public string AirsDayOfWeek
            {
                get
                {
                    return this.airsDayOfWeek;
                }

                set
                {
                    this.airsDayOfWeek = value;
                }
            }

            /// <summary>
            /// Gets or sets the attribute that captures the time of
            /// the day that the TV Show was broadcast.
            /// </summary>
            [DataMember(EmitDefaultValue = false)]
            public string AirsTime
            {
                get
                {
                    return this.airsTime;
                }

                set
                {
                    this.airsTime = value;
                }
            }

            /// -------------------------------------------------------------------------------------------------
            /// <summary>  Gets the list of the Characters associated with this TVSeries. </summary>
            /// <remarks>    The method author was Jock, on the 05/08/2011. </remarks>
            /// <returns>   The characters. </returns>
            /// -------------------------------------------------------------------------------------------------
            [DataMember]
            public List<TVCharacter> Characters
            {
                get
                {
                    return this.characterDictionary.Values.ToList();
                }
            }

            /// <summary>
            /// Gets the list of Genre into which this TVSeries falls/is categorised.
            /// </summary>
            public List<Genre> Genre
            {
                get
                {
                    throw new System.NotImplementedException();
                }

                internal set
                {
                }
            }

            /// -------------------------------------------------------------------------------------------------
            /// <summary> Gets the list season for this TVSeries. </summary>
            /// <value> The list seasons. </value>
            /// -------------------------------------------------------------------------------------------------
            [DataMember]
            public List<TVSeason> ListSeasons
            {
                get
                {
                    var seasons = from season in this.seasonDictionary.Values.ToList()
                                  select season;
                    return seasons.ToList();
                }
            }
        #endregion  Public Properties

        #region Public Operations

            /// -------------------------------------------------------------------------------------------------
            /// <summary>   Gets the specified TVSeason. </summary>
            /// <remarks>    The method author was Jock, on the 05/08/2011. </remarks>
            /// <exception cref="RequestElementNotInDictionaryException"> Thrown when
            /// the requested Season is not in the TVSeries. </exception>
            /// <param name="seasonId"> Identifier for the season. </param>
            /// <returns>   The TVSeason. </returns>
            /// -------------------------------------------------------------------------------------------------
            public TVSeason GetSeason(string seasonId)
            {
                TVSeason retVal = null;
                if (!this.seasonDictionary.TryGetValue(seasonId, out retVal))
                {
                    throw new RequestElementNotInDictionaryException();
                }

                return retVal;
            }

            /// -------------------------------------------------------------------------------------------------
            /// <summary>   Adds jobRole to this TVSeries. </summary>
            /// <remarks>    The method author was Jock, on the 05/08/2011. </remarks>
            /// <exception cref="NotImplementedException"> Thrown when the requested operation is
            /// unimplemented. </exception>
            /// <typeparam name="R">    Type of the JobRole. </typeparam>
            /// <param name="jobRole">  The job role. </param>
            /// -------------------------------------------------------------------------------------------------
            public void Add<R>(R jobRole) where R : JobRole
            {
                throw new NotImplementedException();
            }
        #endregion  Public Operations

        #region Override Methods
            /// <summary>
            /// Returns a <see cref="T:System.String"></see> that represents the current <see cref="T:System.Object"></see>.
            /// </summary>
            /// <returns>
            /// A <see cref="T:System.String"></see> that represents the current <see cref="T:System.Object"></see>.
            /// </returns>
            public override string ToString()
            {
                StringBuilder sb = new StringBuilder();
                #region Start Logging
                if (logger.IsDebugEnabled)
                {
                    logger.Debug("Entering method: " + ((object)MethodBase.GetCurrentMethod()).ToString());
                    sb.Append("Entering method: " + ((object)MethodBase.GetCurrentMethod()).ToString() + Environment.NewLine);
                }
                #endregion Start Logging

                #region Override ToString() default with reflection
                Type t = this.GetType();
                PropertyInfo[] pis = t.GetProperties();
                for (int i = 0; i < pis.Length; i++)
                {
                    try
                    {
                        PropertyInfo pi = (PropertyInfo)pis.GetValue(i);
                        logger.Debug(
                            string.Format(
                            "{0}: {1}",
                            pi.Name,
                            pi.GetValue(this, new object[] { })));
                        sb.AppendFormat("{0}: {1}" + Environment.NewLine, pi.Name, pi.GetValue(this, new object[] { }));
                    }
                    catch (Exception ex)
                    {
                        if (logger.IsDebugEnabled)
                        {
                            logger.Debug("An Exception occured in TVSeries.ToString() ->" + Environment.NewLine + ex.ToString());
                        }
                    }
                }
                #endregion Override ToString() default with reflection

                return sb.ToString();
            }

        #endregion Override Methods

        #region Internal Operations

                /// -------------------------------------------------------------------------------------------------
                /// <summary>   Adds a TVSeason object to this TVSeries.  </summary>
                /// <remarks>    The method author was Jock, on the 05/08/2011. </remarks>
                /// <param name="season">   The season. </param>
                /// -------------------------------------------------------------------------------------------------
                internal void AddSeason(TVSeason season)
                {
                    if (!this.seasonDictionary.ContainsKey(season.Id))
                    {
                        this.seasonDictionary.Add(season.Id, season);
                    }
                }

                /// -------------------------------------------------------------------------------------------------
                /// <summary>   Adds a Character to this TVSeries.  </summary>
                /// <remarks>    The method author was Jock, on the 05/08/2011. </remarks>
                /// <param name="character">    The character. </param>
                /// -------------------------------------------------------------------------------------------------
                internal void AddCharacter(TVCharacter character)
                {
                    if (!this.characterDictionary.ContainsKey(character.Name))
                    {
                        this.characterDictionary.Add(character.Name, character);
                    }
                }

        #endregion Internal Operations
    }
}

/// -------------------------------------------------------------------------------------------------
// End of TVSeries.cs
/// -------------------------------------------------------------------------------------------------
